/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package net.hnilica.cisteniulic.dto;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;

import org.apache.commons.collections.comparators.NullComparator;

/**
 *
 * @author swosh
 */
@Entity
@Table(name = "termin")
@IdClass(TerminCisOriId.class)
public class TerminCisOri implements Serializable, Comparable<TerminCisOri> {

    private static final long serialVersionUID = 2L;
    private String nazUlice;
    private Date terCis;
    private String nazAkce;
    private Set<Integer> cisOrientacni;
    private static Comparator<String> nullSafeComparator = new NullComparator(String.CASE_INSENSITIVE_ORDER);

    public TerminCisOri() {
    }

    public TerminCisOri(String nazUlice) {
        this.nazUlice = nazUlice;
    }

    public TerminCisOri(String nazUlice, Date terCis) {
        this.nazUlice = nazUlice;
        this.terCis = terCis;
    }

    public TerminCisOri(String nazUlice, Date terCis, String nazAkce) {
        this.nazUlice = nazUlice;
        this.terCis = terCis;
        this.nazAkce = nazAkce;
    }

    public TerminCisOri(String nazUlice, Date terCis, String nazAkce, Set<Integer> cisOrientacni) {
        this.nazUlice = nazUlice;
        this.terCis = terCis;
        this.nazAkce = nazAkce;
        this.cisOrientacni = cisOrientacni;
    }

    @Id
    @Column(name = "naz_ulice", nullable = false)
    public String getNazUlice() {
        return nazUlice;
    }

    public void setNazUlice(String nazUlice) {
        this.nazUlice = nazUlice;
    }

    @Temporal(javax.persistence.TemporalType.TIMESTAMP)
    @Column(name = "termin_cisteni", nullable = false)
    public Date getTerCis() {
        return terCis;
    }

    public void setTerCis(Date terCis) {
        this.terCis = terCis;
    }

    @Id
    @Column(name = "naz_akce", nullable = false)
    public String getNazAkce() {
        return nazAkce;
    }

    public void setNazAkce(String nazAkce) {
        this.nazAkce = nazAkce;
    }

    /**
     * 
     * @return
     */
    
    @ElementCollection(fetch=FetchType.EAGER)
    @CollectionTable(name = "cis_orientacni", joinColumns = {
        @JoinColumn(name = "naz_ulice", referencedColumnName = "naz_ulice"),
        @JoinColumn(name = "naz_akce", referencedColumnName = "naz_akce")})
    @Column(name = "cislo")
    public Set<Integer> getCisOrientacni() {
        return cisOrientacni;
    }

    public void setCisOrientacni(Set<Integer> cisOrientacni) {
        this.cisOrientacni = cisOrientacni;
    }

    /**
     * TODO CHANGED
     * Comparator for TerminCisOri. At the first compare terms of cleaning (terCis). On the bottom
     * (lesser ranking)  puts earlier date. Year 2000 is lesser then 1900. If dates is same then
     * sorts naem of street lixicongraphiclly by using String method compareToIgnoreCase.
     *
     * @param o TerminCisOri
     * @return int 1 before, 0 equals, -1 after or null
     */
    public int compareTo(TerminCisOri o) {

        int result = nullSafeComparator.compare(this.getNazAkce(), o.getNazAkce());
        if (result > 0) {
            return 1;
        } else if (result < 0) {
            return -1;
        } else {
            result = nullSafeComparator.compare(this.getNazUlice(), o.getNazUlice());
            if (result > 0) {
                return 1;
            } else if (result < 0) {
                return -1;
            } else {
                return compareToCisOri(o);
            }
        }
    }

    private int compareToCisOri(TerminCisOri o) {
        if (this.getCisOrientacni() == null && o.getCisOrientacni() != null) {
            return 1;
        }
        if (this.getCisOrientacni() != null && o.getCisOrientacni() == null) {
            return -1;
        }
        if (this.getCisOrientacni() == null && o.getCisOrientacni() == null) {
            return this.compareToTerCis(o);
        }
        TreeSet<Integer> cisOriThis = new TreeSet<Integer>(this.getCisOrientacni());
        TreeSet<Integer> cisOriO = new TreeSet<Integer>(o.getCisOrientacni());
        if (cisOriThis.higher(cisOriO.last()) != null) {
            return 1;
        }
        if (cisOriO.higher(cisOriThis.last()) != null) {
            return -1;
        }

        return this.compareToTerCis(o);


    }

    private int compareToTerCis(TerminCisOri o) {
        int result;
        if (this.getTerCis() == null && o.getTerCis() != null) {
            return 1;
        }
        if (this.getTerCis() != null && o.getTerCis() == null) {
            return -1;
        }
        if (this.getTerCis() == null && o.getTerCis() == null) {
            return 0;
        }
        result = this.getTerCis().compareTo(o.getTerCis());
        if (result > 0) {
            return 1;
        } else if (result < 0) {
            return -1;
        } else {
            return 0;
        }

    }

    @Override
    public boolean equals(Object object) {
        if (this == object) {
            return true;
        }
        if (object == null || (object.getClass() != this.getClass())) {
            return false;
        }
        TerminCisOri terminCisOri = (TerminCisOri) object;
        int result = nullSafeComparator.compare(this.getNazAkce(), terminCisOri.getNazAkce());
        if (result != 0) {
            return false;
        }
        result = nullSafeComparator.compare(this.getNazUlice(), terminCisOri.getNazUlice());
        if (result != 0) {
            return false;
        }
        result = compareToCisOri(terminCisOri);
        if (result != 0) {
            return false;
        }
        result = compareToTerCis(terminCisOri);
        if (result != 0) {
            return false;
        }
        return true;


    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 31 * hash + (null == nazAkce ? 0 : nazAkce.hashCode());
        hash = 31 * hash + (null == nazUlice ? 0 : nazUlice.hashCode());
        hash = 31 * hash + (null == cisOrientacni ? 0 : cisOrientacni.hashCode());
        hash = 31 * hash + (null == terCis ? 0 : terCis.hashCode());
        return hash;
    }

    @Override
    public String toString() {
        StringBuilder sB = new StringBuilder();
        if (nazAkce != null) {
            sB.append(nazAkce);
        } else {
            sB.append("null");
        }
        sB.append(", ");
        if (nazUlice != null) {
            sB.append(nazUlice);
        } else {
            sB.append("null");
        }
        sB.append(", ");
        if (cisOrientacni != null) {
            boolean first = true;
            for (Iterator<Integer> it = cisOrientacni.iterator(); it.hasNext();) {
                Integer i = it.next();
                if (first) {
                    first = false;
                    sB.append(i);
                } else {
                    sB.append(", ").append(i);
                }
            }
        } else {
            sB.append("null");
        }
        sB.append(", ");
        if (terCis != null) {
            SimpleDateFormat sdf = new SimpleDateFormat("dd. MM. yyyy");
            sB.append(sdf.format(terCis));
        } else {
            sB.append("null");
        }
        sB.append(". ");
        return sB.toString();
    }

    public String toStringNotEndDot() {
        StringBuilder sB = new StringBuilder();
        if (nazAkce != null) {
            sB.append(nazAkce);
        } else {
            sB.append("null");
        }
        sB.append(", ");
        if (nazUlice != null) {
            sB.append(nazUlice);
        } else {
            sB.append("null");
        }
        sB.append(", ");
        if (cisOrientacni != null) {
            boolean first = true;
            for (Iterator<Integer> it = cisOrientacni.iterator(); it.hasNext();) {
                Integer i = it.next();
                if (first) {
                    first = false;
                    sB.append(i);
                } else {
                    sB.append(", ").append(i);
                }
            }
        } else {
            sB.append("null");
        }
        sB.append(", ");
        if (terCis != null) {
            SimpleDateFormat sdf = new SimpleDateFormat("dd. MM. yyyy");
            sB.append(sdf.format(terCis));
        } else {
            sB.append("null");
        }
        sB.append(" ");
        return sB.toString();
    }

    /**
     *
     */
}
